﻿using System;
using System.IO;
using System.Windows.Forms;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data.SqlServerCe;
using System.ServiceModel;
using System.Diagnostics;
using System.Data.SqlServerCe;
using System.Reflection;
using SyncComm.Proxy;

namespace AppMobileSync
{
    public partial class Form1 : Form
    {
        private readonly string _connectionString = string.Format("Data Source={0}\\SyncSample.sdf;", Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
        private readonly string _pathDb;

        public Form1()
        {
            InitializeComponent();

            using (var connection = new SqlCeConnection(_connectionString))
            {
                _pathDb = connection.Database;
            }

            if (!File.Exists(_pathDb))
            {
                if (MessageBox.Show("Would you like to initalize sync?", "First Time"
                    ,MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                {
                    using (var engine = new SqlCeEngine(_connectionString))
                        engine.CreateDatabase();
                    //let's sync
                    SyncNow();
                }
            }
            else
            {
                if (MessageBox.Show("Previous database has been detected. " +
                    "Would you like to reinitialize it? (Local database will be deleted)", "First Time"
                    , MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                {
                    //delete local database
                    File.Delete(_pathDb);
                    //create database file
                    using (var engine = new SqlCeEngine(_connectionString))
                        engine.CreateDatabase();
                    //and let's sync again
                    SyncNow();
                }
                else
                {
                    //refresh local data grid
                    RefreshDataGrid();
                }
            }
        }

        private void RefreshDataGrid()
        {
            var connection = new SqlCeConnection(_connectionString);
            connection.Open();
            bindingSource1.DataSource =
                new SqlCeCommand("SELECT * FROM [Sales.Customer]", connection).ExecuteReader();
            dataGrid1.Update();
        }

        private void SyncNow()
        {
            try
            {
                //NOTE: For compressed endpoint binding use this
                var endPoint = new EndpointAddress("http://10.0.2.15:9999/SyncService/GZip");
                var s = new ServiceClient(endPoint, BindingType.Compressed);

                //NOTE: For basic endpoint use this
                //var endPoint = new EndpointAddress("http://10.0.2.15:9999/SyncService/Basic");
                //var s = new ServiceClient(endPoint, BindingType.Basic);

                //SqlCe client provider
                var sqlCeClientSyncProvider =
                    new SqlCeClientSyncProvider(_connectionString);

                //agent configuration
                var agent = new SyncAgent
                                {
                                    LocalProvider = sqlCeClientSyncProvider,
                                    RemoteProvider = new ServerSyncProviderProxy(s)
                                };

                //check echo
                var res = s.Echo(sqlCeClientSyncProvider.ClientId.ToString());

                //tracking session progress
                agent.SessionProgress += ((sender, e) =>
                                              {
                                                  this.lblSessionState.Text = e.SyncStage.ToString();

                                                  if (e.BatchProgress != null)
                                                      this.lblInfo.Text =
                                                          string.Format(
                                                              "Syncing batch {0} of {1}. Overall percentage {2}",
                                                              e.BatchProgress.BatchNumber,
                                                              e.BatchProgress.BatchCount, e.PercentCompleted);
                                                  else
                                                  {
                                                      this.lblInfo.Text = string.Format("Overall percentage {0}",
                                                                                        e.PercentCompleted);

                                                  }


                                                  this.statusBar1.Text = string.Format("Syncing... {0}",
                                                                                       e.PercentCompleted.ToString());

                                                  this.progressBar1.Value = e.PercentCompleted;
                                                  this.Refresh();
                                              });

                sqlCeClientSyncProvider.SyncProgress += sqlCeClientSyncProvider_SyncProgress;

                #region Sync tables configuration

                var globalSyncGroup = new SyncGroup("Global");

                //bidirectional sync table
                var customerSyncTable = new SyncTable("Sales.Customer")
                                         {
                                             CreationOption = TableCreationOption.DropExistingOrCreateNewTable,
                                             SyncDirection = SyncDirection.Bidirectional,
                                             SyncGroup = globalSyncGroup
                                         };
                agent.Configuration.SyncTables.Add(customerSyncTable);

                //updloadonly sync table
                var cContactSyncTable = new SyncTable("Sales.CustomerContact")
                                            {
                                                CreationOption = TableCreationOption.UploadExistingOrCreateNewTable,
                                                SyncDirection = SyncDirection.UploadOnly,
                                                SyncGroup = globalSyncGroup
                                            };
                agent.Configuration.SyncTables.Add(cContactSyncTable);
                
                //show sync progress panel
                //TODO...
                this.pSyncProgress.Visible = true;
                this.Refresh();

                //syncing..
                var statistics = agent.Synchronize();

                //check last sync statistics session here...
                Debug.Assert(statistics.TotalChangesDownloaded>0);

                //refresh local data grid
                RefreshDataGrid();

            }
            catch (CFFaultSyncException faultEx)
            {
                Cursor.Current = Cursors.Default;
                
                //
                MessageBox.Show(string.Format("FaultCode: {0}\r\nFaultReason: {1}\r\nHasDetail: {2}", 
                    faultEx.FaultCode, faultEx.FaultMessage, faultEx.HasDetail));
            }
            catch (TargetInvocationException tEx)
            {
                Cursor.Current = Cursors.Default;

                if ((tEx.InnerException != null) && (tEx.InnerException.GetType() == typeof(CFFaultSyncException)))
                    //
                    MessageBox.Show(string.Format("FaultCode: {0}\r\nFaultReason: {1}\r\nHasDetail: {2}",
                                                  (tEx.InnerException as CFFaultSyncException).FaultCode,
                                                  (tEx.InnerException as CFFaultSyncException).FaultMessage,
                                                  (tEx.InnerException as CFFaultSyncException).HasDetail));
                else
                    MessageBox.Show(tEx.Message);   
            }
            catch (CommunicationException communicationException )
            {
                //is the emulator cradled? does it reach SyncService endpoint?
                MessageBox.Show(communicationException.Message);
            }
            catch (Exception e)
            {
                //something is not configured properly
                MessageBox.Show(e.Message);
                //HResult -2146233087 maybe database must be reinitialize

            }
            finally
            {
                this.pSyncProgress.Visible = false;
            }
            #endregion
            
        }

        void sqlCeClientSyncProvider_SyncProgress(object sender, SyncProgressEventArgs e)
        {
            this.lblInfo.Text = "Table " + e.TableMetadata.TableName + " " +e.TableProgress.TotalChanges.ToString();
            this.Refresh();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SyncNow();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void menuItem1_Click(object sender, EventArgs e)
        {
            
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void menuItem4_Click(object sender, EventArgs e)
        {
            //generate Customer ID
            var idCustomer = Guid.NewGuid();

            using (var connection = new SqlCeConnection(_connectionString))
            {
                //Open local database connection
                connection.Open();

                //create SqlCeTransaction object
                var tran = connection.BeginTransaction();
                //create SqlCeCommand for inserting new Sales.Customer row
                var command1 =
                    new SqlCeCommand("INSERT INTO [Sales.Customer] (CustomerId, CustomerName, SalesPerson, CustomerType) " +
                        "VALUES (@id,N'SyncComm Company', N'Joe Doe', N'Reatil')", connection);
                command1.Parameters.Add("@id", idCustomer);
                //enlisting transaction
                command1.Transaction = tran;
                //create SqlCeCommand for inserting new Sales.CustomerContact row
                var command2 =
                    new SqlCeCommand("INSERT INTO [Sales.CustomerContact] ([CustomerId],[PhoneNumber],[PhoneType]) " +
                        "VALUES (@id,N'123456789', N'Mobile')", connection);
                command2.Parameters.Add("@id", idCustomer);
                //enlisting transaction
                command2.Transaction = tran;

                try
                {

                    command1.ExecuteNonQuery();
                    command2.ExecuteNonQuery();
                    
                    //comminting both operations
                    tran.Commit(CommitMode.Deferred);
                }
                catch (Exception)
                {
                    //something was wrong, rolling back transaction
                    tran.Rollback();
                    throw;
                }

            }


            if (MessageBox.Show("A new customer and customer contact have been added. Do you wish to sync now?",
                            "Modifying data",MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                SyncNow();
            else
                RefreshDataGrid();
            
        }

        private void menuItem5_Click(object sender, EventArgs e)
        {

        }

        private void menuItem7_Click(object sender, EventArgs e)
        {
            File.Delete(_pathDb);
        }

        private void menuItem6_Click(object sender, EventArgs e)
        {
            /*NOTE: Not test yet
            
            //TODO: Before this method:
             * Create Foreign key between Customer and CustomerContact on SqlCeClientSyncProvider.CreatingSchema event
             * Then delete a Customer row

            //generate Customer ID
            var idCustomer = Guid.NewGuid();

            using (var connection = new SqlCeConnection(_connectionString))
            {
                //Open local database connection
                connection.Open();

                //create SqlCeTransaction object
                var tran = connection.BeginTransaction();
                //create SqlCeCommand for inserting new Sales.Customer row
                var command1 =
                    new SqlCeCommand("DELETE [Sales.Customer] WHERE CustomerName='SyncComm Company'");
                //enlisting transaction
                command1.Transaction = tran;
                //create SqlCeCommand for inserting new Sales.CustomerContact row
                var command2 =
                    new SqlCeCommand("INSERT INTO [Sales.Error: 5118, Severity: 16, State: 1.] ([CustomerId],[PhoneNumber],[PhoneType]) " +
                        "VALUES (@id,N'123456789', N'Mobile')", connection);
                command2.Parameters.Add("@id", idCustomer);
                //enlisting transaction
                command2.Transaction = tran;

                try
                {

                    command1.ExecuteNonQuery();
                    command2.ExecuteNonQuery();

                    //comminting both operations
                    tran.Commit(CommitMode.Deferred);
                }
                catch (Exception)
                {
                    //something was wrong, rolling back transaction
                    tran.Rollback();
                    throw;
                }

            }


            if (MessageBox.Show("A new customer and customer contact have been added. Do you wish to sync now?",
                            "Modifying data", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                SyncNow();
            else
                RefreshDataGrid();*/
        }
    }
}